Using pre-processed data containing time stamped Vehicle Position Logs (VPLs), I want to create animated maps that show the following:
NOTE: The animate commands take a very long time to run, so make sure you comment them out before running all code chunks.
First, I load in the vehicle position logs along with libraries for aggregating and manipulating data, working with dates, and working with geospatial information. I also load in a shapefile of Calgary community boundaries from the City of Calgary Open Data Catalogue here.
library(tidyverse)
## ── Attaching packages ──────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.2.1 ✓ purrr 0.3.3
## ✓ tibble 2.1.3 ✓ dplyr 0.8.4
## ✓ tidyr 1.0.2 ✓ stringr 1.4.0
## ✓ readr 1.3.1 ✓ forcats 0.4.0
## ── Conflicts ─────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(lubridate)
##
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
##
## date
library(rgdal)
## Loading required package: sp
## rgdal: version: 1.4-8, (SVN revision 845)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
## Path to GDAL shared files: /usr/share/gdal/2.2
## GDAL binary built with GEOS: TRUE
## Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
## Path to PROJ.4 shared files: (autodetected)
## Linking to sp version: 1.3-2
library(rgeos)
## rgeos version: 0.5-2, (SVN revision 621)
## GEOS runtime version: 3.6.2-CAPI-1.10.2
## Linking to sp version: 1.3-2
## Polygon checking: TRUE
library(maptools)
## Checking rgeos availability: TRUE
library(gifski)
library(gganimate)
library(transformr)
vpl_15052019 <- readRDS("vpl_15052019.rds")
community_boundaries <- readOGR("geo_export_e135fc9f-0eec-429a-b94b-14836af732d4.shp")
## OGR data source with driver: ESRI Shapefile
## Source: "/home/alex/Documents/calgary_transit_egs/geo_export_e135fc9f-0eec-429a-b94b-14836af732d4.shp", layer: "geo_export_e135fc9f-0eec-429a-b94b-14836af732d4"
## with 306 features
## It has 7 fields
community_bounds_df <- fortify(community_boundaries,
region = "name")
For this map, I need to have a data frame with the time stamps synchronized so that I can plot them on the same frame. I do this by rounding each time stamp to the nearest 5 minutes, and then aggregating the vehicle positions by taking the mean of the vehicle positions over that 5 minute interval.
vpl_5_min_intervals <- vpl_15052019
vpl_5_min_intervals$vehicle_position_date_time <-
round_date(vpl_5_min_intervals$vehicle_position_date_time,
unit = "5 minutes")
vpl_5_min_intervals <- group_by(vpl_5_min_intervals,
vehicle_position_date_time,
vehicle_id) %>%
summarise(longitude = mean(longitude),
latitude = mean(latitude)) %>%
arrange(vehicle_position_date_time, vehicle_id)
Now I generate the animated map. Note that the transition_states() argument only applies to the layers using the data passed in to ggplot(). Also note that coord_map() uses the mercator projection by default.
p <- ggplot(vpl_5_min_intervals,
aes(x = longitude,
y = latitude)) +
geom_point(aes(group = vehicle_id),
colour = "red") +
labs(title = "Position of YYC Transit Vehicles",
subtitle = "{closest_state}",
caption = "Data: City of Calgary Open Data\nCreated by Alexander Ondrus") +
geom_polygon(data = community_bounds_df,
aes(x = long,
y = lat,
group = group),
fill = NA,
colour = "grey") +
theme_void() +
theme(plot.margin = margin(5,5,5,5)) +
coord_map() +
transition_states(vehicle_position_date_time,
transition_length = 4,
state_length = 1)
animate(p, nframes = 1440, duration = 60)